package com.wgchao.identityrightsmanagement.application.service;

import com.wgchao.identityrightsmanagement.domain.organization.repository.*;
import com.wgchao.identityrightsmanagement.domain.organization.model.*;
import com.wgchao.identityrightsmanagement.infrastructure.exception.ObjectNotExistException;
import com.wgchao.identityrightsmanagement.infrastructure.exception.ObjectNotMatchException;
import com.wgchao.identityrightsmanagement.infrastructure.external.EncodeExternalService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.event.EventListener;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.Date;
import java.util.List;

/**
 * @ClassName: AccountApplicationService
 * @author: wgchao
 * @createTime: 2020/6/8 11:03 AM
 * @Description: TODO
 */
@Service
@Transactional(rollbackFor = Exception.class)
public class AccountApplicationService {
    @Autowired
    private AgencyRepository agencyRepository;
    @Autowired
    private AccountRepository accountRepository;
    @Autowired
    private AssignDepartmentToAccountService assignDepartmentToAccountService;
    @Autowired
    private DepartmentRepository departmentRepository;
    @Autowired
    private ResetAccountOfDepartmentService resetAccountOfDepartment;
    @Autowired
    private EncodeExternalService encodeExternalService;
    @Autowired
    private DepartmentOfficeRepository departmentOfficeRepository;
    @Autowired
    private OfficeRepository officeRepository;
    @Autowired
    private AccountOfficeRepository accountOfficeRepository;
    @Autowired
    private ApplicationEventPublisher publisher;

    //注册管理员账户
    public void addAccount(String agencyCode, AccountCreator accountCreator, String operator){
        Agency agency = agencyRepository.findById(agencyCode);
        if(agency == null){
            throw new ObjectNotExistException("机构不存在");
        }
        //对密码加密
        accountCreator.setPassword(encodeExternalService.encodePWD(accountCreator.getPassword()));
        Account account = Account.registerAccount(accountCreator, agency);
        accountRepository.add(account, operator);
    }

    /**
     * 修改账户基本信息
     * @param username
     * @param accountUpdator
     * @param operator
     */
    public void modifyAccountInfo(String username, AccountUpdator accountUpdator, String operator){
        Account account = accountRepository.findById(username);
        if(account == null){
            throw new ObjectNotExistException("账户不存在");
        }
        Agency agency = agencyRepository.findById(account.getAgencyCode());
        if(agency == null){
            throw new ObjectNotExistException("机构不存在");
        }
        account.modifyAccountInfo(accountUpdator, agency);
        accountRepository.add(account, operator);
    }

    /**
     * 停用账户
     * @param username
     * @param operator
     */
    public void disable(String username, String operator){
        Account account = accountRepository.findById(username);
        if(account == null){
            throw new ObjectNotExistException("账户不存在");
        }
        account.disable();
        accountRepository.add(account, operator);
    }

    /**
     * 启用账户
     * @param username
     * @param operator
     */
    public void regain(String username, String operator){
        Account account = accountRepository.findById(username);
        if(account == null){
            throw new ObjectNotExistException("账户不存在");
        }
        account.regain();
        accountRepository.add(account, operator);
    }

    /**
     * 删除账户
     * @param username
     */
    public void remove(String username, String operator){
        Account account = accountRepository.findById(username);
        if(account == null){
            throw new ObjectNotExistException("账户不存在");
        }
        accountRepository.remove(account, operator);

        //通知 清除账户分配部门角色信息
        publisher.publishEvent(new AccountRemovedEvent(new Date(), username, account.getAgencyCode(), operator));
    }

    public void removeAll(List<String> usernames, String operator){
        for(String username : usernames){
            remove(username, operator);
        }
    }

    //将账户设置到部门
    public void assignAccountToDepartment(String username, String departmentCode, String operator){
        Account account = accountRepository.findById(username);
        if(account == null){
            throw new ObjectNotExistException("账户不存在");
        }
        if(!StringUtils.isEmpty(account.getDepartmentCode())){
            throw new ObjectNotMatchException("账户已经被分配了部门");
        }
        Department department = departmentRepository.findById(departmentCode);
        if(department == null){
            throw new ObjectNotExistException("部门不存在");
        }
        account = assignDepartmentToAccountService.assignDepartmentToAccount(account, department);
        accountRepository.add(account, operator);
    }

    //为账户分配部门职位
    public void assignOfficesToAccount(String username, List<String> officeCodes, String operator){
        Account account = accountRepository.findById(username);
        if(account == null){
            throw new ObjectNotExistException("账户不存在");
        }
        account.ascriptionDepartment();
        Department department = departmentRepository.findById(account.getDepartmentCode());
        if(department == null){
            throw new ObjectNotExistException("账户所在部门不存在");
        }
        // 清空账户职位关系
        accountOfficeRepository.removeByAccount(username);

        for(String officeCode : officeCodes){
            Office office = officeRepository.findById(officeCode);
            if(office == null){
                throw new ObjectNotExistException("职位不存在");
            }

            DepartmentOffice departmentOffice = departmentOfficeRepository
                    .findByDepartmentAndOffice(account.getDepartmentCode(), officeCode);
            if(departmentOffice == null){
                throw new ObjectNotExistException(office.getName()+"职位不属于账户所在部门");
            }
            String identify = accountOfficeRepository.generateCode();
            AccountOffice accountOffice = new AssignOfficesToAccountService(identify, account, department, office, departmentOffice)
                    .assignOfficesToAccount();
            accountOfficeRepository.add(accountOffice, operator);
        }
    }

    /**
     * 账户删除 - 重置账户与部门职位关系
     */
    @EventListener
    public void resetAccountDepartmentOfficeRelationship(AccountRemovedEvent accountRemovedEvent){
        String username = accountRemovedEvent.getUsername();
        accountOfficeRepository.removeByAccount(username);
    }

    /**
     * 职位删除事件-删除账户与部门职位对应关系
     */
    @EventListener
    public void resetAccountDepartmentOfficeRelationship(OfficeRemovedEvent officeRemovedEvent){
        accountOfficeRepository.removeByOffice(officeRemovedEvent.getOfficeCode());
    }

    /**
     * 部门删除事件 重置账户部门
     * @param departmentRemovedEvent
     */
    @EventListener
    public void resetAccountOfDepartment(DepartmentRemovedEvent departmentRemovedEvent) {
        List<Account> accounts = accountRepository.findByDepartment(departmentRemovedEvent.getDepartmentCode());
        if(accounts != null){
            accounts = resetAccountOfDepartment.resetAccountOfDepartment(accounts);
            accountRepository.addAll(accounts, departmentRemovedEvent.getOperator());
        }
    }

    /**
     * 部门删除事件-删除账户与部门职位对应关系
     */
    @EventListener
    public void resetAccountDepartmentOfficeRelationship(DepartmentRemovedEvent departmentRemovedEvent){
        accountOfficeRepository.removeByDepartment(departmentRemovedEvent.getDepartmentCode());
    }

    /**
     * 部门重新分配职位-清除账户所在部门中不存在的职位
     * @param assignedOfficesToDepartmentEvent
     */
    @EventListener
    public void resetAccountDepartmentOfficeRelationship(AssignedOfficesToDepartmentEvent assignedOfficesToDepartmentEvent){
        System.out.println("部门重新分配职位-清除账户所在部门中不存在的职位");
        accountOfficeRepository.cleanUpIllegalCorrespondence(assignedOfficesToDepartmentEvent.getDepartmentCode(),
                assignedOfficesToDepartmentEvent.getOfficeCodes(), assignedOfficesToDepartmentEvent.getOperator());
    }

}
